using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;

namespace DAL
{
    public class Pool : IEnumerable
    {

        static Pool()
        {
            //CleanThread = new System.Threading.Timer(Clean, null, TimeSpan.FromMinutes(5), TimeSpan.FromHours(1));
            CleanThread = new System.Threading.Timer(Clean, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(15));
            //CleanThread = new System.Threading.Timer(Clean, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(2));
        }

        public Pool()
        {
            lock (Pools)
            {
                Pools.Add(new WeakReference(this));
            }
        }

        public static TimeSpan LifeSpan = new TimeSpan(0, 0, 5);
        private static System.Threading.Timer CleanThread;
        private static System.Collections.Generic.List<WeakReference> Pools = new System.Collections.Generic.List<WeakReference>();
        private static void Clean(object State)
        {
            System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest;
            Clean();
        }

        private static void Clean()
        {
            try
            {
                int I = 0;
                while (I != Pools.Count)
                {
                    if (Pools[I].IsAlive)
                    {
                        Pool P = (Pool)Pools[I].Target;
                        System.Collections.Generic.List<long> KeysToRemove = new System.Collections.Generic.List<long>();

                        lock (P.ObjectPool)
                        {
                            foreach (long Key in P.ObjectPool.Keys)
                            {
                                if (!P.ObjectPool[Key].Reference.IsAlive)
                                {
                                    KeysToRemove.Add(Key);
                                }
                            }


                            foreach (long Key in KeysToRemove)
                            {
                                if (P.ObjectPool.ContainsKey(Key))
                                {
                                    P.ObjectPool.Remove(Key);
                                }
                            }
                        }
                        I++;
                    }
                    else
                    {
                        lock (Pools)
                        {
                            Pools.RemoveAt(I);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //LogException(ex);
            }
        }

        public static void Clear()
        {
            int I = 0;
            while (I != Pools.Count)
            {
                if (Pools[I].IsAlive)
                {
                    Pool P = (Pool)Pools[I].Target;
                    lock (P.ObjectPool)
                    {
                        P.ObjectPool.Clear();
                    }
                    I++;
                }
                else
                {
                    lock (Pools)
                    {
                        Pools.RemoveAt(I);
                    }
                }
            }
        }

        System.Collections.Generic.Dictionary<long, PoolItem> ObjectPool = new System.Collections.Generic.Dictionary<long, PoolItem>();

        private object lockobject = new object();
        private PoolItem GetPoolItem(long Key)
        {
            lock (this.ObjectPool)
            {
                if (this.ObjectPool.ContainsKey(Key))
                {
                    PoolItem GetPoolItem = this.ObjectPool[Key];
                    if (GetPoolItem.Reference.IsAlive)
                    {
                        return GetPoolItem;
                    }
                    this.ObjectPool.Remove(Key);
                }
                return null;
            }
        }

        public void TryAdd(long Key, Object Value)
        {
            lock (ObjectPool)
            {
                if (Item(Key) == null)
                {
                    ObjectPool.Add(Key, new PoolItem(Value));
                }
            }
        }

        public void Add(long Key, Object Value)
        {
            lock (ObjectPool)
            {
                ObjectPool.Add(Key, new PoolItem(Value));
            }
        }

        public void TryRemove(long Key)
        {
            lock (ObjectPool)
            {
                if (Item(Key) != null)
                {
                    Remove(Key);
                }
            }
        }

        public void Remove(long Key)
        {
            lock (ObjectPool)
            {
                ObjectPool.Remove(Key);
            }
        }

        public object Item(long Key)
        {
            PoolItem Pooled = GetPoolItem(Key);
            if (Pooled == null)
            {
                return null;
            }
            else
            {
                return Pooled.Reference.Target;
            }
        }

        public bool IsAlive(long Key)
        {
            PoolItem Pooled = GetPoolItem(Key);
            if (Pooled == null)
            {
                return false;
            }
            else
            {
                return ((DateTime.Now - Pooled.Added) < LifeSpan);
            }
        }

        public void BumpItem(long Key)
        {
            PoolItem Item = GetPoolItem(Key);
            if (Item != null)
            {
                Item.Added = DateTime.Now;
            }
        }

        public class PoolItem
        {
            public PoolItem(Object Target)
            {
                Reference = new WeakReference(Target);
                Added = DateTime.Now;
            }

            public WeakReference Reference;
            public DateTime Added;
        }

        public IEnumerator GetEnumerator()
        {
            return new Enumerator(this);
        }

        public class Enumerator : IEnumerator
        {
            // Fields
            private System.Collections.Generic.Dictionary<long, Pool.PoolItem>.Enumerator InnerEnumerator;
            private object LCurrent;

            // Methods
            public Enumerator(Pool P)
            {
                this.InnerEnumerator = P.ObjectPool.GetEnumerator();
            }

            public bool MoveNext()
            {
                bool MoveNext;
                do
                {
                    MoveNext = this.InnerEnumerator.MoveNext();
                }
                while (((MoveNext && !this.InnerEnumerator.Current.Value.Reference.IsAlive) ? 1 : 0) != 0);
                if (MoveNext)
                {
                    this.LCurrent = System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(this.InnerEnumerator.Current.Value.Reference.Target);
                    return MoveNext;
                }
                return false;
            }

            public void Reset()
            {
                ((IEnumerator)this.InnerEnumerator).Reset();
            }

            // Properties
            public object Current
            {
                get
                {
                    return this.LCurrent;
                }
            }

            object System.Collections.IEnumerator.Current
            {
                get
                {
                    return this.LCurrent;
                }
            }
        }
    }
}